package cn.cxj.basic.util;

import cn.cxj.system.domain.Log;
import cn.cxj.system.service.ILogService;
import cn.cxj.system.service.impl.LogServiceImpl;
import com.sun.xml.internal.bind.v2.TODO;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.logging.Logger;

/**
 * 切面类
 * @author 陈鑫杰
 * @date 2022年1月27日16:22:45
 */
@Aspect
@Component
public class LogAspect {

    @Autowired
    private ILogService logService;

    /**
     * 切入点
     */
    @Pointcut("execution(* cn.cxj..*.controller.*Controller.*(..))")
    public void controllerMethod(){
    }

   /* @Before("controllerMethod()")
    public void LogRequestInfo(JoinPoint joinPoint) throws Exception{
        Logger log = Logger.getLogger(String.valueOf(getClass()));
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        log.info("请求地址:"+request.getRequestURL().toString());
        log.info("请求方式:"+request.getMethod());
        log.info("请求类方法:"+joinPoint.getSignature());
        log.info("请求类方法参数:"+ Arrays.toString(joinPoint.getArgs()));
        log.info("请求参数对象:"+joinPoint.getTarget());
        log.info("类的全限定名:"+joinPoint.getTarget().getClass().getName());
    }*/

    @Around("controllerMethod()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        //常见日志实体对象
        Log log = new Log();
        //获取登录用户账户
        /*HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String name = (String) request.getSession().getAttribute("USER_ID");
        log.setUSERID(name);*/
        //获取系统时间
        //获取系统ip,这里用的是我自己的工具类,可自行网上查询获取ip方法
        /*String ip = GetLocalIp.localIp();
        log.setIP(ip);*/
        // 获取用户名 , 先写死
        // TODO: 2022/1/26 等登陆做完后替换
        log.setUsername("陈鑫杰");
        // 获取请求对象
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        // 获取ip地址
        String ip = request.getRemoteAddr();
        log.setIp(ip);
        // 获取url
        String s = request.getRequestURL().toString();
        log.setUrl(s);
        //方法通知前获取时间,为什么要记录这个时间呢？当然是用来计算模块执行时间的
        long start = System.currentTimeMillis();
        // 拦截的实体类，就是当前正在执行的controller
        Object target = pjp.getTarget();
        // 拦截的方法名称。当前正在执行的方法
        String methodName = pjp.getSignature().getName();
        log.setMethod(methodName);
        // 拦截的方法参数
        Object[] args = pjp.getArgs();
        // 拦截的放参数类型
        Signature sig = pjp.getSignature();
        MethodSignature msig = null;
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        msig = (MethodSignature) sig;
        Class[] parameterTypes = msig.getMethod().getParameterTypes();

        Object object = null;
        // 获得被拦截的方法
        Method method = null;
        try {
            method = target.getClass().getMethod(methodName, parameterTypes);
        } catch (NoSuchMethodException e1) {
            e1.printStackTrace();
        } catch (SecurityException e1) {
            e1.printStackTrace();
        }
        if (null != method) {
            // 判断是否包含自定义的注解，说明一下这里的LogAnnotation就是我自己自定义的注解
            if (method.isAnnotationPresent(LogAnnotation.class)) {
                LogAnnotation systemlog = method.getAnnotation(LogAnnotation.class);
                log.setDescription(systemlog.operateType());
                try {
                    object = pjp.proceed();
                    long end = System.currentTimeMillis();
                    //将计算好的时间保存在实体中
                    log.setRuntime(end-start);
                    log.setState("执行成功！");
                    //保存进数据库
                    logService.add(log);
                } catch (Throwable e) {
                    long end = System.currentTimeMillis();
                    log.setRuntime(end-start);
                    log.setState("执行失败");
                    logService.add(log);
                }
            } else {//没有包含注解
                object = pjp.proceed();
            }
        } else { //不需要拦截直接执行
            object = pjp.proceed();
        }
        return object;
    }
}
